#include "qsignalhandler.h"

#include <QDebug>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>

//needed to not get an undefined reference to static members
int QSignalHandler::sighupFd[2];
int QSignalHandler::sigtermFd[2];
int QSignalHandler::sigintFd[2];
int QSignalHandler::sigcontFd[2];

int setup_unix_signal_handlers()
{
    struct sigaction hup, term, sigint, cont;

    hup.sa_handler = QSignalHandler::hupSignalHandler;
    sigemptyset(&hup.sa_mask);
    hup.sa_flags = 0;
    hup.sa_flags |= SA_RESTART;
    if (sigaction(SIGHUP, &hup, 0) > 0)
    {
        return 1;
    }

    term.sa_handler = QSignalHandler::termSignalHandler;
    sigemptyset(&term.sa_mask);
    term.sa_flags = 0;
    term.sa_flags |= SA_RESTART;
    if (sigaction(SIGTERM, &term, 0) > 0)
    {
        return 2;
    }

    sigint.sa_handler = QSignalHandler::intSignalHandler;
    sigemptyset(&sigint.sa_mask);
    sigint.sa_flags = 0;
    sigint.sa_flags |= SA_RESTART;
    if (sigaction(SIGINT, &sigint, 0) > 0)
    {
        return 3;
    }

    cont.sa_handler = QSignalHandler::contSignalHandler;
    sigemptyset(&cont.sa_mask);
    cont.sa_flags = 0;
    cont.sa_flags |= SA_RESTART;
    if (sigaction(SIGCONT, &cont, 0) > 0)
    {
        return 4;
    }

    return 0;
}

QSignalHandler::QSignalHandler(QObject *parent)
    : QObject(parent)
{
    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd))
    {
        qFatal("Couldn't create HUP socketpair");
    }

    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd))
    {
        qFatal("Couldn't create TERM socketpair");
    }

    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd))
    {
        qFatal("Couldn't create INT socketpair");
    }

    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigcontFd))
    {
        qFatal("Couldn't create STOP socketpair");
    }

    snHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this);
    connect(snHup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));

    snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
    connect(snTerm, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));

    snInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this);
    connect(snInt, SIGNAL(activated(int)), this, SLOT(handleSigInt()));

    snCont = new QSocketNotifier(sigcontFd[1], QSocketNotifier::Read, this);
    connect(snCont, SIGNAL(activated(int)), this, SLOT(handleSigCont()));
}

QSignalHandler::~QSignalHandler()
{

}

void QSignalHandler::hupSignalHandler(int )
{
    char a = 1;
    ::write(sighupFd[0], &a, sizeof(a));
}

void QSignalHandler::termSignalHandler(int )
{
    char a = 1;
    ::write(sigtermFd[0], &a, sizeof(a));
}

void QSignalHandler::intSignalHandler(int )
{
    char a = 1;
    ::write(sigintFd[0], &a, sizeof(a));
}

void QSignalHandler::contSignalHandler(int )
{
    char a = 1;
    ::write(sigcontFd[0], &a, sizeof(a));
}

void QSignalHandler::handleSigHup()
{
    snHup->setEnabled(false);
    char tmp;
    ::read(sighupFd[1], &tmp, sizeof(tmp));

    qDebug() << "Sig hup here";

    snHup->setEnabled(true);
}

void QSignalHandler::handleSigTerm()
{
    snTerm->setEnabled(false);
    char tmp;
    ::read(sigtermFd[1], &tmp, sizeof(tmp));

    qDebug() << "Sig term here";

    snTerm->setEnabled(true);
}

void QSignalHandler::handleSigInt()
{
    snInt->setEnabled(false);
    char tmp;
    ::read(sigintFd[1], &tmp, sizeof(tmp));

    qWarning() << "Sig int here";

    snInt->setEnabled(true);
}

void QSignalHandler::handleSigCont()
{
    snCont->setEnabled(false);
    char tmp;
    ::read(sigcontFd[1], &tmp, sizeof(tmp));

    signal(SIGCONT, 0);

    qWarning() << "Sig cont here";

    snCont->setEnabled(true);
}
